<template>
    <div v-bind="$attrs">
        <video ref="previewVideoElement" autoplay controls style="width:100%;border: 1px solid #ccc;"></video>
        <div v-if="!disabled" style="display:flex;">
            <el-button v-if="!uploading" :type="recording ? 'danger' : ''" @click="doRecord">
            {{ recording ? "停止" : "录制"}}</el-button>
            <span v-if="recording">{{ elapsedTime }} 秒</span>
            <el-button v-if="!recording && recordedVideo" :disabled="uploading" @click="uploadVideo">上传</el-button>
            <span style="flex:1;"></span>
            <el-button icon="Refresh" circle @click="switchCamera"/>
        </div>
        <el-progress v-if="uploading" :percentage="percent" style="width:100%;" class="pic-icon" />
    </div>
</template>

<script>
export default {
    name: "MyVideoRecord",
    emits: ["update:modelValue", "uploadOK"],
    props: {
        modelValue: String,
        disabled: Boolean,
        formData: Object,
        extData: {
            type: Object,
            default: function () { return {} },
        },
        server: {
            type: String,
            default: "/Common/UploadFile"
        },
    },
    data() {
        return {
            stream: null,//视频流
            recording: false, // 是否正在录制
            recordedBlobs: [], // 录制完成后的视频数据数组
            mediaRecorder: null, // 媒体录制器
            recordedVideo: null, // 已录制的视频数据
            videoUrl: null, // 渲染已录制的视频URL
            recordedVideoSize: null, // 已录制的视频大小（字节）
            startTime: null, // 录制开始时间
            elapsedTime: 0, // 已录制的时间（秒）
            percent: 0,//上传进度
            uploading: false,//是否正在上传
            camera: "front",
        };
    },
    created() {
        this.videoUrl = $store.getUrl(this.modelValue);
    },
    mounted() {
        //this.getMediaStream();
    },
    unmounted() {
        this.closeStream(this.stream);
    },
    watch: {
        modelValue() {
            this.videoUrl = $store.getUrl(this.modelValue);
        },
        videoUrl() {
            if (this.$refs.previewVideoElement) {
                this.$refs.previewVideoElement.srcObject = null;
                this.$refs.previewVideoElement.src = this.videoUrl;
            }
        },
        camera() {
            if (this.recording) {
                this.stopRecording();
            }
        }
    },
    methods: {
        switchCamera(){
            if(this.recording){
                this.stopRecording();
            }
            if(this.camera=="front"){
                this.camera = "back";
            }else{
                this.camera = "front";
            }
        },
        async getMediaStream() {
            try {
                navigator.getUserMedia = navigator.getUserMedia
                    || navigator.webkitGetUserMedia
                    || navigator.mozGetUserMedia
                    || navigator.msGetUserMedia
                    || window.getUserMedia;

                const constraints = {
                    video: {
                        facingMode: this.camera == "front" ? "user" : { exact: "environment" }
                    },
                    audio: true
                };
                const stream = await navigator.mediaDevices.getUserMedia(constraints);

                this.mediaRecorder = new MediaRecorder(stream);
                this.mediaRecorder.ondataavailable = (event) => {
                    if (event.data.size > 0) {
                        this.recordedBlobs.push(event.data);
                    }
                };
                this.mediaRecorder.onstop = (event) => {
                    const recordedBlob = new Blob(this.recordedBlobs,
                        { type: "video/webm" });
                    this.recordedVideoSize = recordedBlob.size;
                    this.recordedVideo = recordedBlob;
                    this.videoUrl = window.URL.createObjectURL(recordedBlob);

                    this.closeStream(this.stream);
                    this.stream = null;
                    this.mediaRecorder = null;
                };

                this.stream = stream;
            } catch (error) {
                $msg.error("开启录制失败：" + error);
                throw error;
            }
        },
        doRecord() {
            if (this.recording) {
                this.stopRecording();
            } else {
                this.startRecording();
            }
        },
        async startRecording() {
            if (this.recording) return;

            this.recording = true;
            try {
                if (!this.mediaRecorder) {
                    await this.getMediaStream()
                }

                this.startTime = Date.now();
                this.recordedBlobs = [];
                this.recordedVideo = null;
                this.mediaRecorder.start();
                this.updateElapsedTime();
                this.$nextTick(() => {
                    this.$refs.previewVideoElement.src = null;
                    this.$refs.previewVideoElement.srcObject = this.stream;
                });
            } catch (e) {
                this.recording = false;
            }
        },

        stopRecording() {
            if (this.mediaRecorder) {
                this.recording = false;
                this.mediaRecorder.stop();
            }
        },
        closeStream(stream) {
            if (!stream) return;
            if (typeof stream.stop === 'function') {
                stream.stop();
            } else {
                let trackList = [stream.getAudioTracks(), stream.getVideoTracks()];

                for (let i = 0; i < trackList.length; i++) {
                    let tracks = trackList[i];
                    if (tracks && tracks.length > 0) {
                        for (let j = 0; j < tracks.length; j++) {
                            let track = tracks[j];
                            if (typeof track.stop === 'function') {
                                track.stop();
                            }
                        }
                    }
                }
            }
        },
        updateElapsedTime() {
            setInterval(() => {
                if (this.recording) {
                    this.elapsedTime = ((Date.now() - this.startTime) / 1000.0).toFixed(2);
                }
            }, 200);
        },
        uploadVideo() {
            // 在这里编写上传视频的逻辑
            // 可以通过this.recordedVideo获取录制完成后的视频数据，然后执行上传操作
            let time = (new Date()).getTime();
            let fileName = `${time}.mp4`  // 可自定义文件名称
            var file = new File([this.recordedVideo], fileName, {
                type: 'video/mp4'
            });
            var formData = new FormData();
            formData.append("fileName", fileName);
            formData.append("file", file);
            this.post(null, formData, fileName);
        },
        post: function (rawFile, formData, fileName) {
            this.uploading = true;
            const xhr = new XMLHttpRequest()
            const action = $store.UploadServer ? $store.UploadServer : this.server;

            var that = this;
            if (xhr.upload) {
                xhr.upload.onprogress = function progress(e) {
                    if (e.total > 0) {
                        e.percent = parseFloat((e.loaded / e.total * 100).toFixed(2));
                        that.percent = e.percent;
                    }
                }
            }
            that.percent = 0
            formData = formData || new FormData();

            if (this.extData) {
                Object.keys(this.extData).forEach(key => {
                    formData.append(key, this.extData[key])
                })
            }

            if (rawFile != null) {
                formData.append("file", rawFile, rawFile.name);
            }


            xhr.onerror = function error() {
                that.percent = 0;
                that.uploading = false;
                that.onError(xhr)
            }

            xhr.onload = function onload() {
                if (xhr.status < 200 || xhr.status >= 300) {
                    that.onError(xhr)
                    return
                }
                var text = xhr.responseText || xhr.response
                try {
                    text = JSON.parse(text)
                } catch {

                }
                that.uploading = false;
                that.percent = 0;
                that.recordedVideo = null;
                if (text.success) {
                    that.$emit("uploadOK", { url: text.url, name: text.name || fileName });
                }
                that.onSuccess(text)
            }

            xhr.open('post', action, true)

            if ('withCredentials' in xhr) {
                xhr.withCredentials = true
            }

            const headers = that.headers || {}

            for (const item in headers) {
                if (headers.hasOwnProperty(item) && headers[item] !== null) {
                    xhr.setRequestHeader(item, headers[item])
                }
            }
            xhr.send(formData)
            return xhr

        },
        onSuccess: function (res) {
            //在这里处理服务端返回的附件路径
            if (!res.success) {
                $msg.error(res.message)
                return
            }

            this.$emit('update:modelValue', res.url)
        },
        onError: function (err) {
            $msg.message(err, "error");
        },
    }
}
</script>